```src/renderer/views/train/index.vue
<template>
  <div class="common-layout">
    <div style="font-size: 26px; margin-bottom: 10px">
      <el-breadcrumb :separator-icon="ArrowRight">
        <el-breadcrumb-item :to="{ path: '/' }"><span style="color: #c2c6cc">首页</span></el-breadcrumb-item>
        <el-breadcrumb-item :to="{ path: '/thematic-education' }">
          <span style="color: #c2c6cc">文件上传</span></el-breadcrumb-item>
      </el-breadcrumb>
    </div>
    <div>
      <el-row :gutter="20">
        <!-- 左侧树结构 -->
        <el-col :span="4" class="left-tree">
          <el-input v-model="filterText" style="max-width: 600px" placeholder="请输入名称" class="input-with-select">
            <template #append>
              <el-button :icon="Plus" @click="addTopLevel" />
            </template>
          </el-input>
          <el-tree ref="treeRef" :data="treeData" :props="treeProps" node-key="id" default-expand-all
            class="tree-container filter-tree" @node-contextmenu="handleNodeContextmenu"
            :filter-node-method="filterNode" />
        </el-col>
        <!-- 右侧上传区域 -->
        <el-col :span="20">
          <el-upload class="upload-demo" drag action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
            multiple>
            <el-icon class="el-icon--upload"><upload-filled /></el-icon>
            <div class="el-upload__text">
              拖拽文件或 <em>点击文件上传</em>
            </div>
            <template #tip>
              <div class="el-upload__tip">
                只能上传MP4格式的视频文件，文件大小不能超过500MB
              </div>
            </template>
          </el-upload>
        </el-col>
      </el-row>
    </div>
    <div v-show="contextMenuVisible" class="context-menu"
      :style="{ left: contextMenuLeft + 'px', top: contextMenuTop + 'px' }">
      <div class="menu-item" @click="addSubNode" v-if="currentNode?.data?.level !== 1">
        增加下级节点
      </div>
      <div class="menu-item" @click="renameNode">修改名称</div>
      <div class="menu-item danger" @click="deleteNode"
        v-if="currentNode?.data?.level !== 0 || (currentNode?.data?.level === 0 && !currentNode?.data?.children?.length)">
        删除节点
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  computed,
  ref,
  watch,
  onMounted,
  nextTick,
  onUnmounted,
  onBeforeUnmount,
} from "vue";
import type { TreeInstance } from 'element-plus'
import { ElNotification, ElMessageBox } from 'element-plus'
import { Plus, Search } from '@element-plus/icons-vue'
import { ArrowRight } from "@element-plus/icons-vue";
//导入timer.ts
import { useRouter } from "vue-router";
const router = useRouter();
import { openDefenseApi, closeDefenseApi } from "@renderer/api/face";
import { User } from "@renderer/bean/user";
import type { ComponentSize } from "element-plus";
import { status, data, send, open } from "@renderer/utils/websocket";

const filterText = ref('')
const treeRef = ref<TreeInstance>()
watch(filterText, (val) => {
  treeRef.value!.filter(val)
})

const filterNode = (value: string, data: Tree) => {
  if (!value) return true
  return data.label.includes(value)
}

interface Tree {
  [key: string]: any
}
// 树结构数据
const treeData = ref([
  {
    id: 1,
    label: '安全教育视频',
    checked: true,
    level: 0,
    children: [
      { id: 11, label: '施工安全', level: 1, },
      { id: 12, label: '设备操作', level: 1 },
      { id: 13, label: '应急预案', level: 1 }
    ]
  },
  {
    id: 2,
    checked: false,
    level: 0,
    label: '警示教育视频',
    children: [
      { id: 11, label: '施工安全', level: 1, },
      { id: 12, label: '设备操作', level: 1 },
      { id: 13, label: '应急预案', level: 1 }
    ]
  }
])
const treeProps = {
  children: 'children',
  label: 'label'
}
const contextMenuVisible = ref(false)
const contextMenuLeft = ref(0)
const contextMenuTop = ref(0)
let currentNode = ref(null)

const handleNodeContextmenu = (event, data, node) => {
  event.preventDefault()
  currentNode.value = node
  contextMenuLeft.value = event.clientX
  contextMenuTop.value = event.clientY
  contextMenuVisible.value = true
}

const addTopLevel = () => {
  treeData.value.push({
    id: Date.now(),
    label: '新节点',
    level: 0,
    children: []
  })
  contextMenuVisible.value = false
}


const deleteNode = () => {
  if (currentNode.value.parent) {
    const parent = currentNode.value.parent
    const index = parent.children.indexOf(currentNode.value)
    parent.children.splice(index, 1)
  } else {
    const index = treeData.value.findIndex(n => n.id === currentNode.value.id)
    treeData.value.splice(index, 1)
  }
  contextMenuVisible.value = false
}

const renameNode = () => {
  console.log(currentNode.value)
  if (!currentNode.value?.data) {  // 添加data存在性检查
    ElNotification.error('未找到节点数据')
    return
  }

  ElMessageBox.prompt('请输入新名称', '修改名称', {
    inputValue: currentNode.value.data.label,
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    inputValidator: (value) => {
      if (!value?.trim()) return '名称不能为空'
    }
  }).then(({ value }) => {
    currentNode.value.label = value.trim()
    ElNotification.success('修改成功')
  }).catch(() => { })
  contextMenuVisible.value = false
}

const addSubNode = () => {
  ElMessageBox.prompt('请输入子节点名称', '新增子节点', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    inputValidator: (value) => {
      if (!value?.trim()) return '名称不能为空'
    }
  }).then(({ value }) => {
    if (currentNode.value) {
      if (!currentNode.value.children) {
        currentNode.value.children = []
      }
      currentNode.value.children.push({
        id: Date.now(),
        label: value.trim(),
        level: currentNode.value.level + 1
      })
      ElNotification.success('添加成功')
    }
  }).catch(() => { })
  contextMenuVisible.value = false
}

// 添加点击外部关闭菜单的监听
document.addEventListener('click', () => {
  contextMenuVisible.value = false
})
// 上传处理函数
const handleSuccess = (response) => {
  ElNotification.success('上传成功')
}

const handleError = (error) => {
  ElNotification.error('上传失败')
}
// 在组件挂载时启动倒计时
onMounted(() => {

});
//组件销毁时关闭抓拍
onUnmounted(() => {

});
</script>

<style scoped lang="scss">
@import "./css/index.scss";
</style>
